/****************************************************
	文件：AssetLoader.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2020/12/20 18:4:43
	功能：Asset 加载器
*****************************************************/

using System;
using HTFW.Core;
using HTFW.Logger;
using HTFW.Utility.Global;
using UnityEngine;
using Object = UnityEngine.Object;

namespace HTFW.Res
{
    public class AssetLoader : IResLoader
    {
        public int ObjectPoolIndex { get; set; }

        public void Dispose()
        {
        }

        public void LoadSync(ResData assetRes)
        {
            if (assetRes.ResType != ResType.Asset) return;

#if UNITY_EDITOR
            if (ResService.IsSimulationMode) //模拟模式
            {
                LoadAsync(assetRes, null);
                return;
            }
#endif

            if (assetRes.LoadState == ResLoadState.Loading) //加载正在加载的资源
            {
                HLog.Error($"LoadSync error! 异步加载时不能同步加载相同资源：{assetRes.Path}");
            }
            else if (assetRes.LoadState == ResLoadState.Loaded)
            {
                HLog.Error($"LoadSync error! 资源 AssetName：{assetRes.AssetName} 已加载");
            }
            else
            {
                assetRes.Priority = ResTaskPriority.Immediately;
                LoadAsync(assetRes, null);
            }
        }

        public ILoadResult LoadAsync(ResData assetRes, Action onCompleted)
        {
            if (assetRes.ResType != ResType.Asset) return null;

#if UNITY_EDITOR
            if (ResService.IsSimulationMode) //模拟模式
            {
                assetRes.LoadState = ResLoadState.Loading;
                
                if (assetRes.IsSprite)
                    assetRes.Obj = UnityEditor.AssetDatabase.LoadAssetAtPath<Sprite>(assetRes.Path);
                else
                    assetRes.Obj = UnityEditor.AssetDatabase.LoadAssetAtPath<Object>(assetRes.Path);

                assetRes.CurCnt = assetRes.TotalCnt;
                assetRes.IncreaseRef();

                ResCache.Instance.Add(assetRes.Path, assetRes);
                
                assetRes.LoadState = ResLoadState.Loaded;

                onCompleted?.Invoke();

                ResClassObjectPool.Instance.DespawnAssetLoader(this);

                return assetRes.AsyncResult;
            }
#endif

            if (assetRes.LoadState == ResLoadState.Loading) //加载正在加载的资源
            {
                assetRes.OnAsyncLoadDone += () =>
                {
                    assetRes.IncreaseRef();

                    onCompleted?.Invoke();

                    ResClassObjectPool.Instance.DespawnAssetLoader(this);
                };
            }
            else if (assetRes.LoadState == ResLoadState.Loaded)
            {
                HLog.Error($"LoadAsync error! 资源 AssetName：{assetRes.AssetName} 已加载");
            }
            else
            {
                assetRes.LoadState = ResLoadState.Loading;

                assetRes.OnAsyncLoadDone = () =>
                {
                    //Asset 加载完成的逻辑
                    assetRes.CurCnt++;

                    assetRes.IncreaseRef();

                    ResCache.Instance.Add(assetRes.Path, assetRes);

                    assetRes.LoadState = ResLoadState.Loaded;

                    onCompleted?.Invoke();

                    ResClassObjectPool.Instance.DespawnAssetLoader(this);
                };

                if (assetRes.DependencyABNameList.IsNullOrEmpty()) //无依赖项
                {
                    if (ResCache.Instance.TryGet(assetRes.ABName, out ResData abRes)) //已加载过 自身AB
                    {
                        abRes.IncreaseRef();

                        assetRes.AB = abRes.AB;

                        assetRes.CurCnt++;

                        ResScheduler.Instance.AddResCommand(assetRes); //加载 Asset
                    }
                    else //首次加载 自身AB
                    {
                        //TODO 加载 Asset
                        if (ResConfig.Instance.TryGet(assetRes.ABName, out abRes))
                        {
                            abRes.Priority = assetRes.Priority;
                            abRes.Init();
                            IResLoader abLoader = ResClassObjectPool.Instance.SpawnABLoader(); //加载 自身 AB
                            abLoader.LoadAsync(abRes, () =>
                            {
                                assetRes.AB = abRes.AB;

                                assetRes.CurCnt++;

                                ResScheduler.Instance.AddResCommand(assetRes); //加载 Asset
                            });
                        }
                        else
                        {
                            HLog.Error($"LoadAsync error! 资源配置中不存在：{assetRes.ABName}");
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < assetRes.DependencyABNameList.Count; i++)
                    {
                        if (ResCache.Instance.TryGet(assetRes.DependencyABNameList[i], out ResData abRes)) //已加载过 依赖项
                        {
                            abRes.IncreaseRef();

                            assetRes.DependencyABCompletedCount++;
                            assetRes.CurCnt++;
                            if (assetRes.DependencyABCompletedCount == assetRes.DependencyABNameList.Count)
                            {
                                if (ResCache.Instance.TryGet(assetRes.ABName, out ResData ownABRes)) //已加载过 自身AB
                                {
                                    ownABRes.IncreaseRef();

                                    assetRes.AB = ownABRes.AB;

                                    assetRes.CurCnt++;

                                    ResScheduler.Instance.AddResCommand(assetRes); //加载 Asset
                                }
                                else //首次加载 自身AB
                                {
                                    //TODO 加载 Asset
                                    if (ResConfig.Instance.TryGet(assetRes.ABName, out ownABRes))
                                    {
                                        ownABRes.Priority = assetRes.Priority;
                                        ownABRes.Init();
                                        IResLoader ownABLoader = ResClassObjectPool.Instance.SpawnABLoader(); //加载 自身 AB
                                        ownABLoader.LoadAsync(ownABRes, () =>
                                        {
                                            assetRes.AB = ownABRes.AB;

                                            assetRes.CurCnt++;

                                            ResScheduler.Instance.AddResCommand(assetRes); //加载 Asset
                                        });
                                    }
                                    else
                                    {
                                        HLog.Error($"LoadAsync error! 资源配置中不存在：{assetRes.ABName}");
                                    }
                                }
                            }
                        }
                        else //首次加载 依赖项
                        {
                            if (ResConfig.Instance.TryGet(assetRes.DependencyABNameList[i], out abRes))
                            {
                                abRes.Priority = assetRes.Priority;
                                abRes.Init();
                                IResLoader abLoader = ResClassObjectPool.Instance.SpawnABLoader(); //加载 AB 依赖项
                                abLoader.LoadAsync(abRes, () =>
                                {
                                    assetRes.DependencyABCompletedCount++;
                                    assetRes.CurCnt++;
                                    if (assetRes.DependencyABCompletedCount == assetRes.DependencyABNameList.Count)
                                    {
                                        if (ResCache.Instance.TryGet(assetRes.ABName, out ResData ownABRes)) //已加载过 自身AB
                                        {
                                            ownABRes.IncreaseRef();

                                            assetRes.AB = ownABRes.AB;

                                            assetRes.CurCnt++;

                                            ResScheduler.Instance.AddResCommand(assetRes); //加载 Asset
                                        }
                                        else //首次加载 自身AB
                                        {
                                            //TODO 加载 Asset
                                            if (ResConfig.Instance.TryGet(assetRes.ABName, out ownABRes))
                                            {
                                                ownABRes.Priority = assetRes.Priority;
                                                ownABRes.Init();
                                                IResLoader ownABLoader =
                                                    ResClassObjectPool.Instance.SpawnABLoader(); //加载 自身 AB
                                                ownABLoader.LoadAsync(ownABRes, () =>
                                                {
                                                    assetRes.AB = ownABRes.AB;

                                                    assetRes.CurCnt++;

                                                    ResScheduler.Instance.AddResCommand(assetRes); //加载 Asset
                                                });
                                            }
                                            else
                                            {
                                                HLog.Error($"LoadAsync error! 资源配置中不存在：{assetRes.ABName}");
                                            }
                                        }
                                    }
                                });
                            }
                            else
                            {
                                HLog.Error($"LoadAsync error! 资源配置中不存在：{assetRes.DependencyABNameList[i]}");
                            }
                        }
                    }
                }
            }

            return assetRes.AsyncResult;
        }
    }
}